home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / dev / gui / FoxGuiSource.lha / FoxLibSource / Menus.c < prev    next >
C/C++ Source or Header  |  2001-07-07  |  18KB  |  645 lines

  1. /* FoxGUI - The fast, flexible, free Amiga GUI system
  2.     Copyright (C) 2001 Simon Fox (Foxysoft)
  3.  
  4. This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  5. Foxysoft: www.foxysoft.co.uk      Email:simon@foxysoft.co.uk                */
  6.  
  7. /******************************************************************************
  8.  * Shared library code.  Cannot call functions which use exit() such as:
  9.  * printf(), fprintf()
  10.  *
  11.  * Otherwise:
  12.  * The linker returns "__XCEXIT undefined" and the program will fail.
  13.  * This is because you must not exit() a library!
  14.  *
  15.  * Also:
  16.  * proto/exec.h must be included instead of clib/exec_protos.h and
  17.  * __USE_SYSBASE must be defined.
  18.  *
  19.  * Otherwise:
  20.  * The linker returns "Absolute reference to symbol _SysBase" and the
  21.  * library crashes.  Presumably the same is true for the other protos.
  22.  ******************************************************************************/
  23.  
  24. #define __USE_SYSBASE
  25.  
  26. #include <proto/mathieeedoubbas.h>
  27. #include <string.h>
  28. #include <math.h>
  29.  
  30. #include <exec/memory.h>
  31. #include <proto/intuition.h>
  32.  
  33. #include "/FoxInclude/foxgui.h"
  34. #include "FoxGuiTools.h"
  35.  
  36. BOOL FOXLIB IsMenuChecked(REGA0 struct MenuItem *mi)
  37. {
  38.     if (mi)
  39.         if (mi->Flags & CHECKED)
  40.             return TRUE;
  41.     return FALSE;
  42. }
  43.  
  44. static BOOL ClearAssocMenuStrip(GuiWindow *win)
  45.     {
  46.     if (win)
  47.         {
  48.         // Clears the menu strip from this window and all associated windows.
  49.         GuiWindow *w = Gui.GWLfirst;
  50.  
  51.         ClearMenuStrip(win->Win);
  52.         // Clear the menu strips of any other windows that use the same menu strip.
  53.         while (w)
  54.             {
  55.             if (w->FirstMenu == win->FirstMenu && w != win)
  56.                 ClearMenuStrip(w->Win);
  57.             w = w->next;
  58.             }
  59.         return TRUE;
  60.         }
  61.     return FALSE;
  62.     }
  63.  
  64. static BOOL SetAssocMenuStrip(GuiWindow *win)
  65.     {
  66.     if (win)
  67.         {
  68.         // Sets the menu strip for this window and all associated windows.
  69.         GuiWindow *w = Gui.GWLfirst;
  70.  
  71.         SetMenuStrip(win->Win, win->FirstMenu);
  72.         // Set the menu strips of any other windows that use the same menu strip.
  73.         while (w)
  74.             {
  75.             if (w->FirstMenu == win->FirstMenu && w != win)
  76.                 SetMenuStrip(w->Win, win->FirstMenu);
  77.             w = w->next;
  78.             }
  79.         return TRUE;
  80.         }
  81.     return FALSE;
  82.     }
  83.  
  84. static BOOL FindMenuItemFromItem(struct MenuItem *start, struct MenuItem *item)
  85.     {
  86.     if (start == item)
  87.         return TRUE;
  88.     if (start->SubItem)
  89.         if (FindMenuItemFromItem(start->SubItem, item))
  90.             return TRUE;
  91.     if (start->NextItem)
  92.         return FindMenuItemFromItem(start->NextItem, item);
  93.     return FALSE;
  94.     }
  95.  
  96. static BOOL FindMenuItem(struct Menu *m, struct MenuItem *item)
  97.     {
  98.     if (item)
  99.         while (m)
  100.             {
  101.             if (m->FirstItem)
  102.                 if (FindMenuItemFromItem(m->FirstItem, item))
  103.                     return TRUE;
  104.             m = m->NextMenu;
  105.             }
  106.     return FALSE;
  107.     }
  108.  
  109. static BOOL ChangeMenuItem(GuiWindow *win, struct MenuItem *item, int flag, BOOL enable)
  110.     {
  111.     Diagnostic("ChangeMenuItem", ENTER, TRUE);
  112.     if (!FindMenuItem(win->FirstMenu, item))
  113.         // The menu item isn't in this window!
  114.         return Diagnostic("ChangeMenuItem", EXIT, FALSE);
  115.     else
  116.         {
  117.         ClearAssocMenuStrip(win);
  118.  
  119.         if (enable)
  120.             item->Flags |= flag; // Set the flag
  121.         else if (item->Flags & flag)
  122.             item->Flags &= ~flag; // Clear the flag
  123.  
  124.         SetAssocMenuStrip(win); // Reset the menu strip
  125.         }
  126.     return Diagnostic("ChangeMenuItem", EXIT, TRUE);
  127.     }
  128.  
  129. BOOL FOXLIB SetMenuChecked(REGA0 GuiWindow *win, REGA1 struct MenuItem *item, REGD0 BOOL checked)
  130.     {
  131.     return ChangeMenuItem(win, item, CHECKED, checked);
  132.     }
  133.  
  134. BOOL FOXLIB DisableMenuItem(REGA0 GuiWindow *win, REGA1 struct MenuItem *item)
  135.     {
  136.     return ChangeMenuItem(win, item, ITEMENABLED, FALSE);
  137.     }
  138.  
  139. BOOL FOXLIB EnableMenuItem(REGA0 GuiWindow *win, REGA1 struct MenuItem *item)
  140.     {
  141.     return ChangeMenuItem(win, item, ITEMENABLED, TRUE);
  142.     }
  143.  
  144. static BOOL FindMenu(GuiWindow *win, struct Menu *menu)
  145.     {
  146.     if (win && menu)
  147.         {
  148.         struct Menu *m = win->FirstMenu;
  149.         while (m)
  150.             {
  151.             if (m == menu)
  152.                 return TRUE;
  153.             m = m->NextMenu;
  154.             }
  155.         }
  156.     return FALSE;
  157.     }
  158.  
  159. static BOOL ChangeMenu(GuiWindow *win, struct Menu *menu, BOOL enable, BOOL quick)
  160.     {
  161.     /*    If quick is specified, we're going to bypass all of the checks and we won't reset the menu strip
  162.         either.  This is so that DisableAllMenus() can clear the menu strip, call this function (with
  163.         quick specified) once for each menu and then reset the menu strip. */
  164.     Diagnostic("ChangeMenu", ENTER, TRUE);
  165.     if ((!quick) && !FindMenu(win, menu))
  166.         // The menu isn't in this window!
  167.         return Diagnostic("ChangeMenu", EXIT, FALSE);
  168.     else
  169.         {
  170.         if (!quick)
  171.             ClearAssocMenuStrip(win);
  172.  
  173.         if (enable)
  174.             menu->Flags |= MENUENABLED; // Enable the menu
  175.         else if (menu->Flags & MENUENABLED)
  176.             menu->Flags ^= MENUENABLED; // Disable the menu
  177.  
  178.         if (!quick)
  179.             SetAssocMenuStrip(win); // Reset the menu strip
  180.         }
  181.     return Diagnostic("ChangeMenu", EXIT, TRUE);
  182.     }
  183.  
  184. BOOL FOXLIB DisableMenu(REGA0 GuiWindow *win, REGA1 struct Menu *menu)
  185.     {
  186.     return ChangeMenu(win, menu, FALSE, FALSE);
  187.     }
  188.  
  189. BOOL FOXLIB EnableMenu(REGA0 GuiWindow *win, REGA1 struct Menu *menu)
  190.     {
  191.     return ChangeMenu(win, menu, TRUE, FALSE);
  192.     }
  193.  
  194. BOOL FOXLIB DisableWinMenus(REGA0 GuiWindow *win)
  195.     {
  196.     if (win)
  197.         {
  198.         if (win->FirstMenu)
  199.             {
  200.             struct Menu *m = win->FirstMenu;
  201.             ClearAssocMenuStrip(win);
  202.             while (m)
  203.                 {
  204.                 ChangeMenu(win, m, FALSE, TRUE);
  205.                 m = m->NextMenu;
  206.                 }
  207.             SetAssocMenuStrip(win);
  208.             }
  209.         return TRUE;
  210.         }
  211.     return FALSE;
  212.     }
  213.  
  214. BOOL FOXLIB EnableWinMenus(REGA0 GuiWindow *win)
  215.     {
  216.     if (win)
  217.         {
  218.         if (win->FirstMenu)
  219.             {
  220.             struct Menu *m = win->FirstMenu;
  221.             ClearAssocMenuStrip(win);
  222.             while (m)
  223.                 {
  224.                 ChangeMenu(win, m, TRUE, TRUE);
  225.                 m = m->NextMenu;
  226.                 }
  227.             SetAssocMenuStrip(win);
  228.             }
  229.         return TRUE;
  230.         }
  231.     return FALSE;
  232.     }
  233.  
  234. void FOXLIB SetWinMenuFn(REGA0 GuiWindow *win, REGA1 int (* __far __stdargs fn) (GuiWindow*, struct MenuItem *))
  235.     {
  236.     Diagnostic("SetWinMenuFn", ENTER, TRUE);
  237.     win->MenuFn = fn;
  238.     Diagnostic("SetWinMenuFn", EXIT, TRUE);
  239.     }
  240.  
  241. static long findwidth(char *str, struct TextAttr *font)
  242.     {
  243.     struct IntuiText it;
  244.     
  245.     it.NextText = NULL;
  246.     it.ITextFont = font;
  247.     it.IText = str;
  248.     return IntuiTextLength(&it);
  249.     }
  250.  
  251. static void SetMenuWidth(GuiWindow *win, struct MenuItem *firstitem)
  252.     {
  253.     /* Find the longest menu item */
  254.     struct MenuItem *item = firstitem;
  255.     struct IntuiText *it;
  256.     int width = 0, SubIndicatorWidth = findwidth(";", win->ParentScreen->Font);
  257.     while (item)
  258.         {
  259.         it = (struct IntuiText *) item->ItemFill;
  260.         if (it->NextText)
  261.             width = max(width, it->NextText->LeftEdge + SubIndicatorWidth);
  262.         else
  263.             width = max(width, item->Width);
  264.         item = item->NextItem;
  265.         };
  266.     /* Set every items select bar to the length of the longest */
  267.     item = firstitem;
  268.     while (item)
  269.         {
  270.         it = (struct IntuiText *) item->ItemFill;
  271.         if (it->NextText) /* If there's a sub-menu */
  272.             {
  273.             struct MenuItem *si;
  274.             int leftedge = (3 * width) / 4;
  275.  
  276.             /* Move the sub menu indicator to the right edge of the menu */
  277.             it->NextText->LeftEdge = width - SubIndicatorWidth;
  278.  
  279.             /* Set the left edge of the sub menu items */
  280.             si = item->SubItem;
  281.             while (si)
  282.                 {
  283.                 si->LeftEdge = leftedge;
  284.                 si = si->NextItem;
  285.                 };
  286.             };
  287.         item->Width = width;
  288.         item = item->NextItem;
  289.         };
  290.     }
  291.  
  292. static void ClearText(struct IntuiText *text)
  293.     {
  294.     if (text->NextText)
  295.         ClearText(text->NextText);
  296.     /*    When a submenu is added, the ; character is appended by adding a NextText but the string
  297.         holding the ; is not mallocd but static so check for this. */
  298.     if (strcmp(text->IText, ";"))
  299.         GuiFree(text->IText);
  300.     GuiFree(text);
  301.     }
  302.  
  303. static void ClearMenuItem(struct MenuItem *menuitem)
  304.     {
  305.     if (menuitem->NextItem)
  306.         ClearMenuItem(menuitem->NextItem);
  307.     if (menuitem->SubItem)
  308.         ClearMenuItem(menuitem->SubItem);
  309.     ClearText((struct IntuiText *) menuitem->ItemFill);
  310.     if (menuitem->SelectFill)
  311.         ClearText((struct IntuiText *) menuitem->SelectFill);
  312.     GuiFree(menuitem);
  313.     }
  314.  
  315. static void ClearMenu(struct Menu *menu)
  316.     {
  317.     if (menu->NextMenu)
  318.         ClearMenu(menu->NextMenu);
  319.     if (menu->FirstItem)
  320.         ClearMenuItem(menu->FirstItem);
  321.     GuiFree(menu->MenuName);
  322.     GuiFree(menu);
  323.     }
  324.  
  325. void FOXLIB ClearMenus(REGA0 GuiWindow *win)
  326.     {
  327.     GuiWindow *w = Gui.GWLfirst;
  328.     int found = FALSE;
  329.     Diagnostic("ClearMenus", ENTER, TRUE);
  330.     if (win->FirstMenu)
  331.         {
  332.         if (Gui.CleanupFlag)
  333.           SetLastErr("Window closed before its menus were destroyed.");
  334.         ClearMenuStrip(win->Win);
  335.         /* Check whether in use by other windows */
  336.         while (w)
  337.             {
  338.             if (w->FirstMenu == win->FirstMenu && w != win)
  339.                 found = TRUE;
  340.             w = w->next;
  341.             };
  342.         /* Only free the structures if not still in use */
  343.         if (!found)
  344.             ClearMenu(win->FirstMenu);
  345.         };
  346.     win->FirstMenu = NULL;
  347.     Diagnostic("ClearMenus", EXIT, TRUE);
  348.     }
  349.  
  350. void FOXLIB ShareMenus(REGA0 GuiWindow *dest, REGA1 GuiWindow *source)
  351.     {
  352.     Diagnostic("ShareMenus", ENTER, TRUE);
  353.     if (dest->FirstMenu)
  354.         ClearMenus(dest);
  355.     dest->FirstMenu = source->FirstMenu;
  356.     SetMenuStrip(dest->Win, dest->FirstMenu);
  357.     Diagnostic("ShareMenus", EXIT, TRUE);
  358.     }
  359.  
  360. struct Menu* FOXLIB AddMenu(REGA0 GuiWindow *win, REGA1 char *name, REGD0 int leftedge, REGD1 int enabled)
  361.     {
  362.     struct Menu *NewMenu;
  363.     Diagnostic("AddMenu", ENTER, TRUE);
  364.     if (!(NewMenu = (struct Menu *) GuiMalloc(sizeof(struct Menu), 0)))
  365.         {
  366.         Diagnostic("AddMenu", EXIT, FALSE);
  367.         return NULL;
  368.         };
  369.     if (!(NewMenu->MenuName = (char *) GuiMalloc((strlen(name) + 1) * sizeof(char), 0)))
  370.         {
  371.         GuiFree(NewMenu);
  372.         Diagnostic("AddMenu", EXIT, FALSE);
  373.         return NULL;
  374.         };
  375.     memcpy(NewMenu->MenuName, name, (strlen(name) + 1) * sizeof(char));
  376.     NewMenu->NextMenu = NULL;
  377.     NewMenu->Width = findwidth(name, win->ParentScreen->Font) + 8;
  378.     NewMenu->LeftEdge = leftedge;
  379.     NewMenu->TopEdge = NewMenu->Height = 0;
  380.     NewMenu->FirstItem = NULL;
  381.     NewMenu->Flags = (enabled ? MENUENABLED : 0);
  382.     if (win->FirstMenu)
  383.         {
  384.         struct Menu *mp = win->FirstMenu;
  385.         ClearMenuStrip(win->Win);
  386.         while (mp->NextMenu)
  387.             mp = mp->NextMenu;
  388.         mp->NextMenu = NewMenu;
  389.         }
  390.     else
  391.         win->FirstMenu = NewMenu;
  392.     SetMenuStrip(win->Win, win->FirstMenu);
  393.     Diagnostic("AddMenu", EXIT, TRUE);
  394.     return NewMenu;
  395.     }
  396.  
  397. static struct MenuItem *MakeMenuItem(GuiWindow *win, char *name, char *selname, unsigned short flags, int key, int enabled, int checkit, int checked, int menutoggle)
  398.     {
  399.     int SelFillLen, ItemFillLen;
  400.     struct MenuItem *m;
  401.     struct IntuiText *ItemFill, *SelectFill;
  402.     Diagnostic("MakeMenuItem", ENTER, TRUE);
  403.     if (!(m = (struct MenuItem *) GuiMalloc(sizeof(struct MenuItem), 0)))
  404.         {
  405.         Diagnostic("MakeMenuItem", EXIT, FALSE);
  406.         return NULL;
  407.         };
  408.     if (!(ItemFill = (struct IntuiText *) GuiMalloc(sizeof(struct IntuiText), 0)))
  409.         {
  410.         GuiFree(m);
  411.         Diagnostic("MakeMenuItem", EXIT, FALSE);
  412.         return NULL;
  413.         };
  414.     if (!(ItemFill->IText = (char *) GuiMalloc((strlen(name) + 1) * sizeof(char), 0)))
  415.         {
  416.         GuiFree(ItemFill);
  417.         GuiFree(m);
  418.         Diagnostic("MakeMenuItem", EXIT, FALSE);
  419.         return NULL;
  420.         };
  421.     if (selname)
  422.         {
  423.         if (!(SelectFill = (struct IntuiText *) GuiMalloc(sizeof(struct IntuiText), 0)))
  424.             {
  425.             GuiFree(ItemFill->IText);
  426.             GuiFree(ItemFill);
  427.             GuiFree(m);
  428.             Diagnostic("MakeMenuItem", EXIT, FALSE);
  429.             return NULL;
  430.             };
  431.         if (!(SelectFill->IText = (char *) GuiMalloc((strlen(selname) + 1) * sizeof(char), 0)))
  432.             {
  433.             GuiFree(SelectFill);
  434.             GuiFree(ItemFill->IText);
  435.             GuiFree(ItemFill);
  436.             GuiFree(m);
  437.             Diagnostic("MakeMenuItem", EXIT, FALSE);
  438.             return NULL;
  439.             };
  440.         memcpy(SelectFill->IText, selname, (strlen(selname) + 1) * sizeof(char));
  441.         SelectFill->FrontPen = win->NewWin.DetailPen;
  442.         SelectFill->BackPen = win->NewWin.BlockPen;
  443.         SelectFill->DrawMode = JAM2;
  444.         SelectFill->LeftEdge = (checkit ? CHECKWIDTH : 2);
  445.         SelectFill->TopEdge = 0;
  446.         SelectFill->ITextFont = win->ParentScreen->Font;
  447.         SelectFill->NextText = NULL;
  448.         }
  449.     else
  450.         SelectFill = NULL;
  451.  
  452.     memcpy(ItemFill->IText, name, (strlen(name) + 1) * sizeof(char));
  453.     ItemFill->FrontPen = win->NewWin.DetailPen;
  454.     ItemFill->BackPen = win->NewWin.BlockPen;
  455.     ItemFill->DrawMode = JAM2;
  456.     ItemFill->LeftEdge = (checkit ? CHECKWIDTH : 2);
  457.     ItemFill->TopEdge = 0;
  458.     ItemFill->ITextFont = win->ParentScreen->Font;
  459.     ItemFill->NextText = NULL;
  460.     m->ItemFill = (APTR) ItemFill;
  461.     m->SelectFill = (APTR) SelectFill;
  462.     m->NextItem = NULL;
  463.     SelFillLen = SelectFill ? IntuiTextLength(SelectFill) : 0;
  464.     ItemFillLen = IntuiTextLength(ItemFill);
  465.     m->Width = max(SelFillLen, ItemFillLen) + (checkit ? CHECKWIDTH : 0) + (key > 0 ? 40 : 0) + 10;
  466.     m->Height = win->ParentScreen->Font->ta_YSize;
  467.     m->Command = (char) key;
  468.     m->SubItem = NULL;
  469.     m->Flags = ITEMTEXT | (selname ? HIGHIMAGE : HIGHCOMP) | (key > 0 ? COMMSEQ : 0) | (enabled ? ITEMENABLED : 0) | (checkit ? CHECKIT : 0) | (checked ? CHECKED : 0) | (checkit && menutoggle ? MENUTOGGLE : 0);
  470.     m->MutualExclude = 0; /* !!! For now... */
  471.  
  472.     Diagnostic("MakeMenuItem", EXIT, TRUE);
  473.     return m;
  474.     }
  475.  
  476. BOOL FOXLIB RemoveMenuItem(REGA0 GuiWindow *win, REGA1 struct MenuItem *item)
  477.     {
  478.     struct Menu *m;
  479.     int itemheight;
  480.  
  481.     if (!(win && item && win->FirstMenu))
  482.         return FALSE;
  483.  
  484.     // First check that the item is in the window's menu structure
  485.     m = win->FirstMenu;
  486.     while (m)
  487.         {
  488.         struct MenuItem *mi = m->FirstItem, *pi = NULL;
  489.         while (mi)
  490.             {
  491.             if (mi == item)
  492.                 {
  493.                 // Found the item, let's remove it.
  494.                 struct MenuItem *nmi = mi->NextItem;
  495.                 itemheight = mi->Height;
  496.                 ClearAssocMenuStrip(win);
  497.                 if (pi)
  498.                     pi->NextItem = nmi;
  499.                 else
  500.                     m->FirstItem = nmi;
  501.                 if (mi->SubItem)
  502.                     ClearMenuItem(mi->SubItem);
  503.                 if (mi->ItemFill)
  504.                     ClearText((struct IntuiText *) mi->ItemFill);
  505.                 if (mi->SelectFill)
  506.                     ClearText((struct IntuiText *) mi->SelectFill);
  507.                 GuiFree(mi);
  508.                 while (nmi)
  509.                     {
  510.                     nmi->TopEdge -= itemheight;
  511.                     nmi = nmi->NextItem;
  512.                     }
  513.                 SetAssocMenuStrip(win);
  514.                 return TRUE;
  515.                 }
  516.             pi = mi;
  517.             mi = mi->NextItem;
  518.             }
  519.         m = m->NextMenu;
  520.         }
  521.     return FALSE;
  522.     }
  523.  
  524. struct MenuItem* FOXLIB AddMenuItem(REGA0 GuiWindow *win, REGA1 struct Menu *menu, REGA2 char *name, REGA3 char *selname,
  525.         REGD0 unsigned short flags, REGD1 int key, REGD2 int enabled, REGD3 int checkit, REGD4 int checked, REGD5 int menutoggle)
  526.     {
  527.     struct MenuItem *m, *lastitem = NULL, *item = menu->FirstItem;
  528.     Diagnostic("AddMenuItem", ENTER, TRUE);
  529.     if (!(m = MakeMenuItem(win, name, selname, flags, key, enabled, checkit, checked, menutoggle)))
  530.         {
  531.         Diagnostic("AddMenuItem", EXIT, FALSE);
  532.         return NULL;
  533.         };
  534.  
  535.     m->LeftEdge = 0;
  536.     m->TopEdge = 0;
  537.     while (item)
  538.         {
  539.         m->TopEdge = m->TopEdge + item->Height;
  540.         lastitem = item;
  541.         item = item->NextItem;
  542.         };
  543.  
  544.     ClearMenuStrip(win->Win);
  545.     if (lastitem)
  546.         lastitem->NextItem = m;
  547.     else
  548.         menu->FirstItem = m;
  549.  
  550.     SetMenuWidth(win, menu->FirstItem);
  551.     SetMenuStrip(win->Win, win->FirstMenu);
  552.     
  553.     Diagnostic("AddMenuItem", EXIT, TRUE);
  554.     return m;
  555.     }
  556.  
  557. struct MenuItem* FOXLIB AddSubMenuItem(REGA0 GuiWindow *win,
  558.         REGA1 struct MenuItem *menuitem, REGA2 char *name, REGA3 char *selname, REGD0 unsigned short flags,
  559.         REGD1 int key, REGD2 int enabled, REGD3 int checkit, REGD4 int checked, REGD5 int menutoggle)
  560.     {
  561.     struct Menu *ParentMenu = NULL, *CheckMenu = win->FirstMenu;
  562.     struct MenuItem *m, *lastitem = NULL, *item = menuitem->SubItem, *CheckItem, *CheckSubItem;
  563.     Diagnostic("AddSubMenuItem", ENTER, TRUE);
  564.  
  565.     /* Check whether the parent is already a subitem.  If so, reject */
  566.     while (CheckMenu)
  567.         {
  568.         CheckItem = CheckMenu->FirstItem;
  569.         while (CheckItem)
  570.             {
  571.             if (CheckItem == menuitem)
  572.                 ParentMenu = CheckMenu;
  573.             CheckSubItem = CheckItem->SubItem;
  574.             while (CheckSubItem)
  575.                 {
  576.                 if (menuitem == CheckSubItem)
  577.                     {
  578.                     /* The parent is already a subitem so reject */
  579.                     Diagnostic("AddSubMenuItem", EXIT, FALSE);
  580.                     return NULL;
  581.                     };
  582.                 CheckSubItem = CheckSubItem->NextItem;
  583.                 };
  584.             CheckItem = CheckItem->NextItem;
  585.             };
  586.         CheckMenu = CheckMenu->NextMenu;
  587.         };
  588.  
  589.     /* If the parent doesn't yet have any sub items, initialise it */
  590.     if (!menuitem->SubItem)
  591.         {
  592.         int SelFillLen, ItemFillLen;
  593.         struct IntuiText *it, *sf;
  594.         /* Remove the hot key if it has one */
  595.         menuitem->Command = (char) 0;
  596.         /* Add the ; character to the parent menu to indicate the sub menu */
  597.         it = (struct IntuiText *) menuitem->ItemFill;
  598.         sf = (struct IntuiText *) menuitem->SelectFill;
  599.         if (!(it->NextText = (struct IntuiText *) GuiMalloc(sizeof(struct IntuiText), 0)))
  600.             {
  601.             Diagnostic("AddSubMenuItem", EXIT, FALSE);
  602.             return NULL;
  603.             };
  604.         it->NextText->IText = ";";
  605.         it->NextText->FrontPen = it->FrontPen;
  606.         it->NextText->BackPen = it->BackPen;
  607.         it->NextText->DrawMode = it->DrawMode;
  608.         SelFillLen = sf ? IntuiTextLength(sf) : 0;
  609.         ItemFillLen = IntuiTextLength(it);
  610.         it->NextText->LeftEdge = max(SelFillLen, ItemFillLen) + findwidth("x", it->ITextFont);
  611.         it->NextText->TopEdge = it->TopEdge;
  612.         it->NextText->ITextFont = it->ITextFont;
  613.         it->NextText->NextText = NULL;
  614.         };
  615.  
  616.     if (!(m = MakeMenuItem(win, name, selname, flags, key, enabled, checkit, checked, menutoggle)))
  617.         {
  618.         Diagnostic("AddSubMenuItem", EXIT, FALSE);
  619.         return NULL;
  620.         };
  621.  
  622.     m->TopEdge = 0;
  623.     while (item)
  624.         {
  625.         m->TopEdge = m->TopEdge + item->Height;
  626.         lastitem = item;
  627.         item = item->NextItem;
  628.         };
  629.  
  630.     ClearMenuStrip(win->Win);
  631.     if (lastitem)
  632.         lastitem->NextItem = m;
  633.     else
  634.         menuitem->SubItem = m;
  635.  
  636.     if (ParentMenu)
  637.         SetMenuWidth(win, ParentMenu->FirstItem);
  638.     m->LeftEdge = (3 * ParentMenu->FirstItem->Width) / 4;
  639.     SetMenuWidth(win, menuitem->SubItem);
  640.     SetMenuStrip(win->Win, win->FirstMenu);
  641.     
  642.     Diagnostic("AddSubMenuItem", EXIT, TRUE);
  643.     return m;
  644.     }
  645.